
// sys
#include <string.h>
#include <stdexcept>
// mine
#include "bit_reader.h"

namespace msgutils {

namespace {
class RawReadBuffer : public IReadBuffer {
 public:
  RawReadBuffer(const uint8_t* buffer, size_t size) 
      : buf_(buffer), size_(size), pos_(0) {}

  virtual uint8_t operator[](size_t index) const {
    index += pos_;
    if (index >= size_)
      throw index_out_of_range();
    return buf_[index]; 
  }

  virtual void Drain(size_t size) {
    if (pos_ + size > size_)
      throw insufficient_buffer_to_drain();
    pos_ += size;
  }

  virtual void Copyout(uint8_t* data, size_t size) {
    if (pos_ + size > size_)
      throw insufficient_buffer_to_copy();

    memcpy(data, buf_ + pos_, size);
  }

  virtual void Read(uint8_t* data, size_t size) {
    Copyout(data, size);
    Drain(size);
  }

  virtual void Reset(void) { pos_ = 0; }

  virtual size_t Bytes(void) const { return size_ - pos_; }

  virtual size_t BytesRead(void) const { return pos_; }

 private:
  const uint8_t* buf_;
  size_t size_;
  size_t pos_;
};
}

void BitReader::Construct(const uint8_t* buffer, size_t size) {
  rbuf_ = new RawReadBuffer(buffer, size);
  delete_rbuf_ = true;
}

BitReader::BitReader(IReadBuffer* read_buffer) 
    : rbuf_(read_buffer), delete_rbuf_(false) {}

BitReader::BitReader(const uint8_t* buffer, size_t size)
    : rbuf_(NULL), delete_rbuf_(false) {
  Construct(buffer, size);
}

BitReader::~BitReader(void) {
  if (delete_rbuf_)
    delete rbuf_;
}

void BitReader::Read(char* string) {
  size_t len;
  Read(len);
  rbuf_->Read((uint8_t*)string, len);
  string[len] = '\0';
}

namespace {
template<class T>
size_t DecodeNumberInternal(T& val, const uint8_t in[], size_t len) {
  val = 0;
  bool finish = false;
  size_t bytes = 0;
  for (; bytes < len && !finish; ++bytes) {
    uint8_t lower = in[bytes];
    if (lower & 0x80)
      lower &= 0x7f;
    else 
      finish = true;

    val |= lower << (7 * bytes);
  }

  if (!finish) throw decode_number_failed();
  return bytes;
}
}

size_t BitReader::DecodeNumber(size_t bits, void* number_addr, bool drain) {
  uint8_t buf[10];
  size_t len = rbuf_->Bytes() < 10 ? rbuf_->Bytes() : 10;
  rbuf_->Copyout(buf, len);
  size_t bytes = 0;
  if (bits == 8)
    bytes = DecodeNumberInternal(*(uint8_t*)number_addr, buf, len);
  else if (bits == 16)
    bytes = DecodeNumberInternal(*(uint16_t*)number_addr, buf, len);
  else if (bits == 32)
    bytes = DecodeNumberInternal(*(uint32_t*)number_addr, buf, len);
  if (bits == 64)
    bytes = DecodeNumberInternal(*(uint64_t*)number_addr, buf, len);

  if (drain)
    rbuf_->Drain(bytes);
  return bytes;
}

size_t BitReader::BytesRead(void) const {
  return rbuf_->BytesRead();
}


}

